package com.serena.da.rest.data_providers.xlsx;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.testng.ITestContext;
import org.testng.annotations.DataProvider;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Created by Spitkovskyi Igor on 8/24/2014.
 */
public class XLSXDataProvider {
    protected static XSSFWorkbook dataworkbook;
    private static String currentPathToXLSXFile;

    public static XSSFWorkbook getWorkbookInstance(String inputFile) throws Exception{
        if(dataworkbook == null || !currentPathToXLSXFile.equalsIgnoreCase(inputFile)) {
            currentPathToXLSXFile = inputFile;
            File xlsxfile = new File(inputFile);
            FileInputStream fin = new FileInputStream(xlsxfile);
            dataworkbook = new XSSFWorkbook(fin);
            fin.close();
        }

        return dataworkbook;
    }

    public static XSSFSheet getDataWorksheet (ITestContext context, String WorkSheetName) throws Exception{
        XSSFSheet worksheet = null;

        //Get path to the datafile.
        String inputFile = context.getCurrentXmlTest().getParameter("filenamePath");
        if(inputFile.isEmpty()){
            throw new Exception("No path to data file has been provided.");
        }

        dataworkbook = getWorkbookInstance(inputFile);

        worksheet = dataworkbook.getSheet(WorkSheetName);

        return worksheet;
    }

    @DataProvider
    public static Iterator<Object[]> getDataSetsFromXLSX (ITestContext context) throws Exception{
        //Get name of worksheet to work with from corresponding parameter in Suite-XML
        String worksheetName = context.getCurrentXmlTest().getParameter("worksheetName");

        //Container for data, matching format of TestNG data providers.
        XSSFSheet dataSheet = getDataWorksheet(context, worksheetName);

        //Container for data, matching format of TestNG data providers.
        List<Object[]> dataToBeReturned = new ArrayList<Object[]>();

        //Iterate through rows which contain data.
        Iterator<Row> rowsIterator = dataSheet.rowIterator();
        int expectedNumberOfParameters = 0;
        boolean headerRowSkipped = false;

        while(rowsIterator.hasNext()){
            Row row = rowsIterator.next();
            //Determine index of first and last cell with data
            short firstcell = row.getFirstCellNum();
            short lastcell = row.getLastCellNum();

            //Skip top row, which contains headers.
            if(!headerRowSkipped){
                headerRowSkipped = true;
                //Determine required number of parameters by number of column headers.
                expectedNumberOfParameters = lastcell - firstcell;
                continue;
            }

            ArrayList<Object> createComponentParameters = new ArrayList<>(expectedNumberOfParameters);

            //Check if number of parameters specified in row equals to number of column headers in the worksheet.
            if(lastcell - firstcell < expectedNumberOfParameters){
                System.out.println("ERROR: Data set (=row) is not correct. Some parameters (values in columns) were not found. Please check data in the XLSX data file. Skip creation of component for this data set.");
                continue;
            }

            for(int i=firstcell; i<lastcell; i++){
                Cell cell = row.getCell(i, Row.CREATE_NULL_AS_BLANK);
                switch(cell.getCellType()){
                    case  Cell.CELL_TYPE_BOOLEAN:
                        createComponentParameters.add(((Boolean) row.getCell(i, Row.CREATE_NULL_AS_BLANK).getBooleanCellValue()).toString());
                        break;
                    case Cell.CELL_TYPE_NUMERIC:
                        createComponentParameters.add(((Double)row.getCell(i, Row.CREATE_NULL_AS_BLANK).getNumericCellValue()).toString());
                        break;
                    default:
                        createComponentParameters.add(row.getCell(i, Row.CREATE_NULL_AS_BLANK).getStringCellValue());
                        break;
                }
            }

            dataToBeReturned.add(createComponentParameters.toArray(new String[expectedNumberOfParameters]));
        }

        return dataToBeReturned.iterator();
    }
}
